package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.account.AccountDeductVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderDerateMapper orderDerateMapper;
    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private UserAccountFeignClient userAccountFeignClient;

    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //原始金额
        BigDecimal originalAmount = new BigDecimal("0.00");
        BigDecimal derateAmount = new BigDecimal("0.00");
        BigDecimal orderAmount = new BigDecimal("0.00");
        //订单明细
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        //减免明细
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        //获取用户信息
        Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(userId);
        Assert.notNull(userInfoVoResult,"查询用户信息失败");
        UserInfoVo userInfoVo = userInfoVoResult.getData();
        Assert.notNull(userInfoVo,"查询用户信息失败");
        //根据购买类型判断
        if(tradeVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_ALBUM)){
            //判断这个用户是否购买过专辑
            Result<Boolean> isPaidAlbumResult = this.userInfoFeignClient.isPaidAlbum(tradeVo.getItemId());
            Assert.notNull(isPaidAlbumResult, "查询用户是否购买专辑失败");
            Boolean result = isPaidAlbumResult.getData();
            if(result){
                //用户购买过专辑
                throw new GuiguException(ResultCodeEnum.REPEAT_BUY_ERROR);
            }
            //购买专辑
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(tradeVo.getItemId());
            Assert.notNull(albumInfoResult,"查询专辑信息失败|");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo,"查询专辑信息失败");

            //获取原价
            originalAmount = albumInfo.getPrice();
            //判断用户身份
            if(userInfoVo.getIsVip().intValue() ==1 && userInfoVo.getVipExpireTime().after(new Date())){
                //判断是否有折扣，return xs != ys ? ((xs > ys) ? 1 : -1) : 0;（xs是前者，ys是后者）
                if(albumInfo.getVipDiscount().compareTo(new BigDecimal("-1"))>0){
                    derateAmount = albumInfo.getPrice().multiply(new BigDecimal("10").subtract(albumInfo.getVipDiscount())).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
                }else{
                    //如果没有VIP折扣，判断是否有普通折扣
                    if(albumInfo.getDiscount().compareTo(new BigDecimal("-1"))>0){
                        derateAmount = albumInfo.getPrice().multiply(new BigDecimal("10").subtract(albumInfo.getDiscount())).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
                    }
                }
            }else{
                if(albumInfo.getDiscount().compareTo(new BigDecimal("-1"))>0){
                    //普通折扣
                    derateAmount = albumInfo.getPrice().multiply(new BigDecimal("10").subtract(albumInfo.getDiscount())).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
                }
            }
            //实际金额
            orderAmount = originalAmount.subtract(derateAmount);
            //订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVoList.add(orderDetailVo);
            //减免明细
            if(derateAmount.compareTo(new BigDecimal("0.00"))>0){
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                //赋值
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setRemarks("专辑折扣");
                orderDerateVoList.add(orderDerateVo);
            }
        }else if(tradeVo.getItemType().equals(SystemConstant.ORDER_ITEM_TYPE_TRACK)){
            //购买声音
            //判断当前传递声音数量
            if(tradeVo.getTrackCount()<0){
                throw new GuiguException(ResultCodeEnum.ARGUMENT_VALID_ERROR);
            }
            Result<List<TrackInfo>> trackInfoListResult = trackInfoFeignClient.findPaidTrackInfoList(tradeVo.getItemId(), tradeVo.getTrackCount());
            Assert.notNull(trackInfoListResult,"查询声音信息失败");
            //付费声音列表
            List<TrackInfo> trackInfoList = trackInfoListResult.getData();
            //当前声音Id对应的专辑Id都是同一个
            //获取到专辑对象
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId());
            Assert.notNull(albumInfoResult,"查询专辑信息失败");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo,"查询专辑信息失败");
            //原始金额
            originalAmount = 0 == tradeVo.getTrackCount() ? albumInfo.getPrice() : albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(tradeVo.getTrackCount())));
            orderAmount = originalAmount;
            //构建订单明细
            for(TrackInfo info : trackInfoList){
                //  创建订单明细对象
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                orderDetailVo.setItemName(info.getTrackTitle());
                orderDetailVo.setItemUrl(info.getCoverUrl());
                //  细节记住：属于购买声音的Id，并不是页面传递的声音Id;
                orderDetailVo.setItemId(info.getId());
                orderDetailVoList.add(orderDetailVo);
            }
            //  声音不存在打折，所以没有折扣明细;
        }else{
            //购买Vip
            Long itemId = tradeVo.getItemId();
            Result<VipServiceConfig> vipServiceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(itemId);
            Assert.notNull(vipServiceConfigResult,"查询VIP服务配置失败");
            VipServiceConfig vipServiceConfig = vipServiceConfigResult.getData();
            Assert.notNull(vipServiceConfig,"查询VIP服务配置失败");
            //设置原始金额
            originalAmount = vipServiceConfig.getPrice();
            //减免金额
            derateAmount = originalAmount.subtract(vipServiceConfig.getDiscountPrice());
            //实际金额
            orderAmount = originalAmount.subtract(derateAmount);
            //订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVo.setItemId(itemId);
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVoList.add(orderDetailVo);
            //减免明细
            if(derateAmount.compareTo(new BigDecimal("0.00"))>0){
                //构建对象并赋值
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setRemarks("VIP服务折扣");
                orderDerateVoList.add(orderDerateVo);
            }
        }
        //声明一个订单交易号
        String tradeNo = UUID.randomUUID().toString().replaceAll("-", "");
        //存储到缓存中；判断key可以使用setnx+setex利用锁的思想
        String tradeNoKey = userId + ":" + tradeNo;
        redisTemplate.opsForValue().set(tradeNoKey,tradeNo,3, TimeUnit.MINUTES);
        orderInfoVo.setTradeNo(tradeNo);
        orderInfoVo.setPayWay("");
        orderInfoVo.setItemType(tradeVo.getItemType());
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        orderInfoVo.setTimestamp(SignHelper.getTimestamp());
        //签名；防止用户非法篡改数据保证接口的安全性
        String  orderJson = JSONObject.toJSONString(orderInfoVo);
        String sign = SignHelper.getSign(JSONObject.parseObject(orderJson, Map.class));
        orderInfoVo.setSign(sign);

        //返回数据
        return orderInfoVo;
    }

    @Override
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //1.校验：签名-保证数据接口安全性！校验orderInfoVo数据是否被篡改
        //orderInfovo变为Map集合
        Map map = JSONObject.parseObject(JSONObject.toJSONString(orderInfoVo),Map.class);
        map.put("payWay","");
        SignHelper.checkSign(map);
        //2.校验：防止重复提交订单
        //2.1获取当前页面传递的流水号
        String tradeNo = orderInfoVo.getTradeNo();
        //2.2与redis中缓存的流水号进行比较；单线程-直接使用equals（）；多线程：redis+lua脚本
        String scriptText =  "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                "then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        String tradeNoKey = userId + ":" + tradeNo;
        //创建实体类
        DefaultRedisScript defaultRedisScript = new DefaultRedisScript<>();
        defaultRedisScript.setScriptText(scriptText);
        defaultRedisScript.setResultType(Long.class);
        //调用方法
        Long count = (Long) redisTemplate.execute(defaultRedisScript, Arrays.asList(tradeNoKey),tradeNo);
        //判断
        if(0==count){
            //抛出异常
            throw new GuiguException(ResultCodeEnum.REPEAT_SUBMIT);
        }
        //声明一个订单编号
        String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
        //判断用户选择的支付方式：在线，余额
        if(!orderInfoVo.getPayWay().equals(SystemConstant.ORDER_PAY_ACCOUNT)){
            //在线
            //保存订单交易记录
            saveOrderInfo(orderInfoVo, userId, orderNo);
            //发送延迟消息取消订单
            rabbitService.sendDealyMessage(MqConst.EXCHANGE_CANCEL_ORDER,MqConst.ROUTING_CANCEL_ORDER,orderNo,MqConst.CANCEL_ORDER_DELAY_TIME);
        }else {
            //余额,需要一个远程调用
            //检查和锁定账户金额
            AccountDeductVo accountDeductVo = new AccountDeductVo();
            accountDeductVo.setOrderNo(orderNo);
            accountDeductVo.setUserId(userId);
            accountDeductVo.setAmount(orderInfoVo.getOrderAmount());
            accountDeductVo.setContent("订单支付");
            //远程调用
            Result result = userAccountFeignClient.checkAndDeduct(accountDeductVo);
            //判断
            if(200 !=result.getCode()){
                throw new GuiguException(result.getCode(),result.getMessage());
            }
            //保存订单数据
            saveOrderInfo(orderInfoVo, userId, orderNo);
            //需要修改订单状态
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
            orderInfoMapper.update(orderInfo,new QueryWrapper<OrderInfo>().eq("order_no",orderNo));
            //记录交易记录；远程调用UserInfoFeinClient
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setUserId(userId);
            userPaidRecordVo.setOrderNo(orderNo);
            userPaidRecordVo.setItemType(orderInfoVo.getItemType());
            //购买类目的ID；专辑ID；声音ID；VipId = orderInfoVo。getOrderDetailVolist（）.itemId; = order_detail.item_id;
            List<Long> itemIdList = orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList());
            userPaidRecordVo.setItemIdList(itemIdList);
            //远程调用
            Result userResult = userInfoFeignClient.savePaidRecord(userPaidRecordVo);
            //判断
            if(200!=userResult.getCode()){
                throw new GuiguException(211,"新增购买记录异常");
            }
        }
        return orderNo;
    }

    @Override
    public OrderInfo getOrderInfoByOrderNo(String orderNo) {
        //查看数据库
        OrderInfo orderInfo = this.getOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo,orderNo));
        if(null != orderInfo){
            //获取支付名称
            String payName = orderInfo.getPayWay().equals(SystemConstant.ORDER_PAY_ACCOUNT)? "余额":"在线";
            //设置支付名称
            orderInfo.setPayWayName(payName);
        }
        return orderInfo;
    }

    @Override
    public void cancelOrder(String orderNo) {
        //paymentInfo wepay
        //取消订单
        OrderInfo orderInfo = this.getOrderInfoByOrderNo(orderNo);
        //判断是否为空
        if(null == orderInfo){
            log.info("订单不存在：{}",orderNo);
            return;
        }
        //修改当前状态
        if (orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_PAID)) {
            log.info("订单已支付：{}",orderNo);
            return;
        }
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
        this.updateById(orderInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveOrderInfo(OrderInfoVo orderInfoVo, Long userId, String orderNo) {
        //order_info
        OrderInfo orderInfo = new OrderInfo();
        //属性拷贝
        BeanUtils.copyProperties(orderInfoVo,orderInfo);
        orderInfo.setUserId(userId);
        orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        orderInfo.setOrderNo(orderNo);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
        orderInfoMapper.insert(orderInfo);
        //order_detail
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        if(!CollectionUtils.isEmpty(orderDetailVoList)){
            for(OrderDetailVo orderDetailVo : orderDetailVoList){
                //创建对象
                OrderDetail orderDetail = new OrderDetail();
                //赋值
                orderDetail.setOrderId(orderInfo.getId());
                orderDetail.setItemPrice(orderDetailVo.getItemPrice());
                orderDetail.setItemName(orderDetailVo.getItemName());
                orderDetail.setItemId(orderDetailVo.getItemId());
                orderDetail.setItemUrl(orderDetailVo.getItemUrl());
                orderDetailMapper.insert(orderDetail);
            }
        }
        //order_derate
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if(!CollectionUtils.isEmpty(orderDerateVoList)){
            for(OrderDerateVo orderDerateVo : orderDerateVoList){
                //创建减免明细
                OrderDerate orderDerate = new OrderDerate();
                orderDerate.setOrderId(orderInfo.getId());
                orderDerate.setDerateType(orderDerateVo.getDerateType());
                orderDerate.setDerateAmount(orderDerateVo.getDerateAmount());
                orderDerate.setRemarks(orderDerateVo.getRemarks());
                orderDerateMapper.insert(orderDerate);
            }
        }
    }



}
